<?php
/**
 * Created by PhpStorm.
 * User: shaowei
 * Date: 2019/8/27
 * Time: 下午6:33
 */

namespace App\Http\Model;

use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\DB;

class Meet extends Base
{
    private $matchingManKey = 'MEET:MATCHING:MAN';
    private $matchingWomanKey = 'MEET:MATCHING:WOMAN';
    private $matchingMapKey = 'MEET:MATCHING:MAP';
    private $waitKey = 'MEET:WAIT:'; // MEET:WAIT:{meet_id}
    private $configKey = 'MEET:CONFIG:'; // MEET:CONFIG:{meet_id}
    private $noticeBlockKey = 'MEET:BLOCK:'; // MEET:BLOCK:{user_id}

    private $userOnlineFirstManMap = 'MEET:FIRST:USER:MAN';
    private $userOnlineFirstWomanMap = 'MEET:FIRST:USER:WOMAN';
    private $showInformationKey = 'MEET:SHOW:INFORMATION:';// MEET:SHOW:INFORMATION:{meet_id}
    private $meetSuccessKey = 'MEET:SUCCESS:';//MEET:SUCCESS:{meet_id}
    private $meetOnlineUserLevelKeyPrefix = 'MEET:ONLINE:USER:LEVEL:';//在线用户集合
    private $meetOnlineUserLevelManKeyPrefix = 'MEET:ONLINE:USER:LEVEL:MAN:';//在线男用户集合
    private $meetOnlineUserLevelWomanKeyPrefix = 'MEET:ONLINE:USER:LEVEL:WOMAN:';//在线女用户集合

    protected $table = 'meet';

    public function __construct(array $attributes = [])
    {
        parent::__construct($this->table, $attributes);
    }


    /**
     * 添加一个用户到匹配队列
     * @param $gender 0.男 1.女
     * @param $userId
     * @param $back
     * @return integer
     */
    public function addMatching($gender, $userId, $back = false)
    {
        if (Redis::HINCRBY($this->matchingMapKey, $userId . ':inc', 1) > 1) {//用户已经在`邂逅`中了，需要等待匹配结束才能再次加入
            return false;
        }

        Redis::HSET($this->matchingMapKey, $userId, time());//设置用户加入匹配的时间
        $matchingQueueKey = $this->matchingManKey;
        if ($gender == 1) {
            $matchingQueueKey = $this->matchingWomanKey;
        }

        if ($back) {
            return Redis::LPUSH($matchingQueueKey, $userId);//加入队列，从左
        }

        return Redis::RPUSH($matchingQueueKey, $userId);//加入队列,从右
    }


    /**
     * 从匹配队列获取一个用户
     * @param $gender
     * @return null/$userId
     */
    public function getMatching($gender)
    {
        $matchingQueueKey = $this->matchingManKey;
        if ($gender == 1) {
            $matchingQueueKey = $this->matchingWomanKey;
        }

        $userId = Redis::LPOP($matchingQueueKey);
        if (empty($userId)) {
            return null;
        }

        Redis::HDEL($this->matchingMapKey, $userId);
        Redis::HDEL($this->matchingMapKey, $userId . ':inc');
        return $userId;
    }


    /**
     * 获得队列长度
     * @param $gender
     * @return mixed
     */
    public function getMatchingSize($gender)
    {
        $matchingQueueKey = $this->matchingManKey;
        if ($gender == 1) {
            $matchingQueueKey = $this->matchingWomanKey;
        }
        return Redis::LLEN($matchingQueueKey);
    }


    /**
     * 获得队列第一个时间
     * @param $gender
     * @return mixed
     */
    public function getMatchingFirstTime($gender, $index = 0)
    {
        $matchingQueueKey = $this->matchingManKey;
        if ($gender == 1) {
            $matchingQueueKey = $this->matchingWomanKey;
        }
        $userIds = Redis::LRANGE($matchingQueueKey, $index, $index);
        $userId = $userIds[0] ?? 0;
        if (empty($userId)) {
            return null;
        }
        return Redis::HGET($this->matchingMapKey, $userId);
    }


    /**
     * 获取当前匹配的用户ID
     * @return array
     */
    public function getMatchingUserIdArr()
    {
        $userIdArr = Redis::HKEYS($this->matchingMapKey);
        if (empty($userIdArr)) {
            return [];
        }
        return $userIdArr;
    }


    /**
     * 等待
     */
    public function wait($meetId)
    {
        $key = $this->waitKey . $meetId;
        $inc = Redis::INCR($key);
        if (Redis::TTL($key) == -1) {
            Redis::EXPIRE($key, 10);
        }
        return $inc;
    }

    /**
     * 取消等待
     * @param $meetId
     * @return mixed
     */
    public function cancelWait($meetId)
    {
        $key = $this->waitKey . $meetId;
        $inc = Redis::INCRBY($key, -1);
        if (Redis::TTL($key) == -1) {
            Redis::EXPIRE($key, 10);
        }
        return $inc;
    }

    /**
     * 获得等待值 等于2成功
     * @param $meetId
     * @return mixed
     */
    public function getWait($meetId)
    {
        $key = $this->waitKey . $meetId;
        $inc = Redis::GET($key);
        return $inc;
    }


    /**
     * 配置设置结束时间
     * @param $meetId
     * @param $time
     * @return mixed
     */
    public function setTimeOut($meetId, $time)
    {
        Redis::HSET($this->configKey . $meetId, 'timeout', $time);
        $this->ttl($meetId);
    }


    public function incTimeOut($meetId, $time)
    {
        $val = Redis::HINCRBY($this->configKey . $meetId, 'timeout', $time);
        $this->ttl($meetId);
        return intval($val);
    }


    public function ttl($meetId)
    {
        $key = $this->configKey . $meetId;
        if (Redis::TTL($key) == -1) {
            Redis::EXPIRE($key, 3600);
        }
    }


    /**
     * 获取结束时间
     * @param $meetId
     * @return int
     */
    public function getTimeOut($meetId)
    {
        $time = Redis::HGET($this->configKey . $meetId, 'timeout');
        if (empty($time)) {
            return 0;
        }
        return intval($time);
    }


    /**
     * 设置邂逅中性别用户
     * @param $gender
     * @param $meetId
     * @param $userId
     * @return boolean
     */
    public function setUserId($gender, $meetId, $userId)
    {
        $key = 'muserid';
        if ($gender == 1) {
            $key = 'wuserid';
        }
        Redis::HSET($this->configKey . $meetId, $key, $userId);
        $this->ttl($meetId);
    }


    /**
     * 获得邂逅中性别用户
     * @param $gender
     * @param $meetId
     * @return int
     */
    public function getUserId($gender, $meetId)
    {
        $key = 'muserid';
        if ($gender == 1) {
            $key = 'wuserid';
        }
        $mUserId = Redis::HGET($this->configKey . $meetId, $key);
        if (empty($mUserId)) {
            return 0;
        }
        return intval($mUserId);
    }


    /**
     * 设置邂逅中喜欢用户
     * @param $gender
     * @param $meetId
     * @param $userId
     * @return boolean
     */
    public function setLikeUserId($gender, $meetId, $userId)
    {
        $key = 'mlikeuserid';
        if ($gender == 1) {
            $key = 'wlikeuserid';
        }
        Redis::HSET($this->configKey . $meetId, $key, $userId);
        $this->ttl($meetId);
    }


    /**
     * 获得邂逅中喜欢用户
     * @param $gender
     * @param $meetId
     * @return int
     */
    public function getLikeUserId($gender, $meetId)
    {
        $key = 'mlikeuserid';
        if ($gender == 1) {
            $key = 'wlikeuserid';
        }
        $mUserId = Redis::HGET($this->configKey . $meetId, $key);
        if (empty($mUserId)) {
            return 0;
        }
        return intval($mUserId);
    }


    /**
     * 获取礼物数据
     * @return \Illuminate\Support\Collection|mixed
     */
    public function getMeetGift()
    {
        $result = DB::table('meet_gift')->orderBy('sort', 'desc')->get(['type', 'gift_id', 'delay_time']);
        if (empty($result)) {
            return [];
        }
        return self::objToArray($result);
    }

    /**
     * 添加举报
     * @param $userId
     * @param $mUserId
     * @param $wUserId
     * @param $meetId
     * @param $reportType
     * @param $describe
     */
    public function addReport($userId, $mUserId, $wUserId, $meetId, $reportType, $describe, $pics)
    {
        DB::table('meet_report')->insert([
            'user_id' => $userId,
            'man_user_id' => $mUserId,
            'woman_user_id' => $wUserId,
            'report_type' => $reportType,
            'pics' => $pics,
            'audio' => '',
            'meet_id' => $meetId,
            'describe' => $describe,
            'create_timestamp' => time(),
            'dispose' => 0,
            'dispose_desc' => '',
        ]);
    }


    /**
     * 添加通知屏蔽
     * @param $userId
     * @param $time
     */
    public function noticeBlock($userId, $time)
    {
        return Redis::SET($this->noticeBlockKey . $userId, time(), 'EX', $time);
    }


    /**
     * 是否通知屏蔽
     * @param $userId
     * @return mixed
     */
    public function hasNoticeBlock($userId)
    {
        return Redis::EXISTS($this->noticeBlockKey . $userId);
    }

    /**
     * 获取优先用户 男
     * @return array
     */
    public function getOnlineFirstManArr()
    {
        $userIdArr = Redis::HKEYS($this->userOnlineFirstManMap);
        if (empty($userIdArr)) {
            return [];
        }
        return $userIdArr;
    }

    /**
     * 获取优先用户 女
     * @return array
     */
    public function getOnlineFirstWomanArr()
    {
        $userIdArr = Redis::HKEYS($this->userOnlineFirstWomanMap);
        if (empty($userIdArr)) {
            return [];
        }
        return $userIdArr;
    }

    /**
     * 设置优先匹配用户
     * @param $gender
     * @param $userId
     * @return boolean
     */
    public function setFirstUser($gender, $userId)
    {
        $key = $gender == 0 ? $this->userOnlineFirstManMap : $this->userOnlineFirstWomanMap;
        return $ret = Redis::HSET($key, $userId, time());
    }

    /**
     * 删除优先匹配用户
     * @param $gender
     * @param $userId
     * @return boolean
     */
    public function delFirstUser($gender, $userId)
    {
        $key = $gender == 0 ? $this->userOnlineFirstManMap : $this->userOnlineFirstWomanMap;
        return $ret = Redis::HDEL($key, $userId, time());
    }

    /**
     * 获取优先匹配用户
     * @param $gender
     * @param $userId
     * @return boolean
     */
    public function getFirstUser()
    {
        $userOnlineFirstManMapData = Redis::HKEYS($this->userOnlineFirstManMap);
        $userOnlineFirstWomanMapData = Redis::HKEYS($this->userOnlineFirstWomanMap);

        $userOnlineFirstManMapData = $userOnlineFirstManMapData ?? [];
        $userOnlineFirstWomanMapData = $userOnlineFirstWomanMapData ?? [];

        return array_merge($userOnlineFirstManMapData, $userOnlineFirstWomanMapData);
    }

    /**
     * 停止用户匹配
     * @param $gender 0.男 1.女
     * @param $userId
     * @param $back
     * @return integer
     */
    /**
     * 添加一个用户到匹配队列
     * @param $gender 0.男 1.女
     * @param $userId
     * @param $back
     * @return integer
     */
    public function stopMatching($gender, $userId, $back = false)
    {
        $matchingQueueKey = $gender == 1 ? $this->matchingWomanKey : $this->matchingManKey;
        Redis::HDEL($this->matchingMapKey, $userId);
        Redis::HDEL($this->matchingMapKey, $userId . ':inc');
        return Redis::LREM($matchingQueueKey, 1, $userId);
    }


    /**
     * 创建邂逅关系
     * @param string $meetId 邂逅Id（md5串）
     * @param int $launchUser 邀请人Id
     * @param int $inviteesUser 受邀人Id
     * @param int $type 邂逅类型 [1：自动匹配(默认)   2：手动邀请]
     */
    public function createEncounter($meetId, $launchUser, $inviteesUser, $type = 1)
    {
        DB::table('meet_encounter')->insert([
            'meet_id' => $meetId,
            'launch_user' => $launchUser,
            'invitees_user' => $inviteesUser,
            'meet_type' => $type,
            'create_time' => date('Y-m-d H:i:s', time()),
        ]);
    }

    /**
     * 获取邂逅的时间
     *
     * @param string $meetId
     * @return int
     */
    public function getMeetTotalTime(string $meetId): int
    {
        $record = DB::table('meet_encounter')->where(['meet_id' => $meetId])->first();
        if ($record) {
            $record = self::objToArray($record);
            $closeTime = $record['close_time'] ? strtotime($record['close_time']) : time();
            $timeSec = $closeTime - strtotime($record['create_time']);
            return $timeSec < 0 ? 0 : $timeSec;
        }

        return 0;
    }


    /**
     * 设置邂逅关系为关闭状态
     * @param string $meetId 邂逅Id（md5串）
     */
    public function setCloseTime($meetId)
    {
        // 查询邂逅关系是否已经关闭
        $result = DB::table('meet_encounter')->where(['meet_id' => $meetId])->first();
        if ($result) {
            DB::table('meet_encounter')->where(['meet_id' => $meetId])
                ->update(['close_time' => date('Y-m-d H:i:s', time())]);
        }
    }

    /**
     * 更新邂逅开始时间
     *
     * @param string $meetId
     * @return bool
     */
    public function updateMeetCreateTime(string $meetId): bool
    {
        DB::table('meet_encounter')->where(['meet_id' => $meetId])
            ->update(['create_time' => date('Y-m-d H:i:s', time())]);
        return true;
    }

    /**
     * 记录公开身份记录
     *
     * @param string $meetId
     * @param int $userId
     * @return bool
     */
    public function setShowInformationCache(string $meetId, int $userId): bool
    {
        $cacheKey = $this->showInformationKey . $meetId;
        Redis::SADD($cacheKey, $userId);
        Redis::EXPIRE($cacheKey, 24 * 3600);
        if (Redis::SCARD($cacheKey) == 2) {
            return true;
        }

        return false;
    }

    /**
     * 邂逅结束后，清除缓存
     *
     * @param string $meetId
     * @return bool
     */
    public function clearShowInformationCache(string $meetId): bool
    {
        Redis::DEL($this->showInformationKey . $meetId);
        return true;
    }

    /**
     * 检测用户是否公开了身份
     *
     * @param string $meetId
     * @param int $userId
     * @return bool
     */
    public function checkOpenStatus(string $meetId, int $userId): bool
    {
        return boolval(Redis::SISMEMBER($this->showInformationKey . $meetId, $userId));
    }

    /**
     * 设置邂逅成功的缓存
     *
     * @param string $meetId
     * @return bool
     */
    public function setMeetSuccessCache(string $meetId): bool
    {
        $cacheKey = $this->meetSuccessKey . $meetId;
        Redis::SET($cacheKey, 1);
        Redis::EXPIRE($cacheKey, 60);//1分钟
        return true;
    }

    /**
     * 检测是否邂逅成功
     *
     * @param string $meetId
     * @return bool
     */
    public function checkMeetSuccess(string $meetId): bool
    {
        $cacheKey = $this->meetSuccessKey . $meetId;
        return Redis::GET($cacheKey) ? true : false;
    }

    /**
     * 是否互相公开了 true=是 false=不是
     *
     * Created at 2021/10/18 14:13
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param string $meetId
     * @return bool
     */
    public function checkOpenToEachOther(string $meetId): bool
    {
        return Redis::SCARD($this->showInformationKey . $meetId) == 2;
    }

    /**
     * 将用户按照分数存储到集合
     *
     * Created at 2021/10/20 18:01
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $level
     * @param int $userId
     * @return bool
     */
    public function setOnlineUserLevelCache(int $level, int $userId): bool
    {
        $this->deleteOnlineUserLevelCache($userId);
        $cacheKey = $this->meetOnlineUserLevelKeyPrefix . $level;
        Redis::SADD($cacheKey, $userId);//存到集合
        $user = (new User())->get_user($userId);
        if ($user['gender'] == 1) {//男
            $cacheKey = $this->meetOnlineUserLevelManKeyPrefix . $level;
            Redis::SADD($cacheKey, $userId);//存到集合
        } elseif ($user['gender'] == 2) {//女
            $cacheKey = $this->meetOnlineUserLevelWomanKeyPrefix . $level;
            Redis::SADD($cacheKey, $userId);//存到集合
        }
        return true;
    }

    /**
     * 随机从集合中取数据
     *
     * Created at 2021/10/20 18:04
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $level 1/2/3/4
     * @param int $number
     * @param int $gender 1=男 2=女
     * @return array
     */
    public function randomGetOnlineUserIdsByLevel(int $level, int $number, int $gender): array
    {
        if ($gender == 1) {
            $result = Redis::SRANDMEMBER($this->meetOnlineUserLevelManKeyPrefix . $level, $number);
        } elseif ($gender == 2) {
            $result = Redis::SRANDMEMBER($this->meetOnlineUserLevelWomanKeyPrefix . $level, $number);
        } else {
            $result = Redis::SRANDMEMBER($this->meetOnlineUserLevelKeyPrefix . $level, $number);
        }

        return $result ?: [];
    }

    /**
     * 删除用户的缓存
     *
     * Created at 2021/10/20 18:08
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $userId
     * @return bool
     */
    public function deleteOnlineUserLevelCache(int $userId): bool
    {
        $meetRuleNumber = MeetRule::query()->count();
        if ($meetRuleNumber) {
            $levels = range(1, $meetRuleNumber);//一共多少分组
            foreach ($levels as $level) {
                Redis::SREM($this->meetOnlineUserLevelKeyPrefix . $level, $userId);
                Redis::SREM($this->meetOnlineUserLevelManKeyPrefix . $level, $userId);
                Redis::SREM($this->meetOnlineUserLevelWomanKeyPrefix . $level, $userId);
            }
        }

        return true;
    }
}